package com.caifu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caifu.bean.PageDo;
import com.caifu.bean.Result;
import com.caifu.bean.ResultUtil;
import com.caifu.enums.SexTypeEnum;
import com.caifu.mapper.*;
import com.caifu.neums.CognitionStatusEnum;
import com.caifu.pojo.*;
import com.caifu.service.IBillService;
import com.caifu.service.ICostService;
import com.caifu.service.UserInfoService;
import com.caifu.util.*;
import com.caifu.vo.BillListVO;
import com.caifu.vo.ElderlyInfoVO;
import com.github.pagehelper.util.StringUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.io.UTFDataFormatException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class BillServiceImpl implements IBillService {

    @Resource
    private YlDayBillMapper dayBillMapper;
    @Resource
    private YlElderlyInfoMapper elderMapper;
    @Resource
    private YlBuildingMapper ylBuildingMapper;
    @Resource
    private YsLabelMapper ysLabelMapper;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private YlElderlyInfoMapper ylElderlyInfoMapper;
    @Resource
    private YlElderlyBillMapper ylElderlyBillMapper;
    @Resource
    private YlStaffInfoMapper ylStaffInfoMapper;
    @Resource
    private YlCostMapper ylCostMapper;
    @Resource
    private YlContractInfoMapper ylContractInfoMapper;
    @Resource
    private YlNursingRecordMapper ylNursingRecordMapper;
    @Resource
    private YlAssessmentRecordMapper ylAssessmentRecordMapper;
    @Resource
    private YlMonthBillMapper monthBillMapper;
    @Resource
    private YlPaymentRecordMapper payRecordMapper;
    @Resource
    private YlPaymentDetailRecordMapper payDtRecordMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Override
    @Transactional
    public Result createDayBill(String date, String userNo) throws Exception {
        try {
            Map<String,Object> info = dayBillMapper.createDayBill(userNo, date);
            if(info!=null){
                int dayCount = Util.getDaysOfMonth(date); //获取日账单所在月天数

                String bedDegree = formatDegree((long)info.get("bed_cost_no"));
                BigDecimal bedFee = (BigDecimal) info.get("bed_fee");
                double bedFeeDb = MathExtend.divide(bedFee.doubleValue(),(double)dayCount,2);  //计算床位费（床位月费/月天数）
                String nursingDegree = formatDegree((long)info.get("nurse_cost_no"));
                BigDecimal nursingFee = (BigDecimal)info.get("nurse_fee");
                double nursingFeeDb =  MathExtend.divide(nursingFee.doubleValue(),(double)dayCount,2); //计算护理费（护理月费/月天数）
                String assementDegree = formatDegree((long)info.get("assess_cost_no"));
                BigDecimal assementFee = (BigDecimal)info.get("assess_fee");
                double assementFeeDb =  MathExtend.divide(assementFee.doubleValue(),(double)dayCount,2); //计算长护险费（长护险月费/月天数）
                BigDecimal mealFee = (BigDecimal)info.get("food_fee");
                YlDayBill bill = dayBillMapper.selectOne(new QueryWrapper<YlDayBill>().eq("user_no",userNo).eq("bill_date",date));
                if(bill==null){
                    bill = new YlDayBill();
                    bill.setAssementDegree(assementDegree);
                    bill.setAssementFee(assementFeeDb);
                    bill.setBedDegree(bedDegree);
                    bill.setBedFee(bedFeeDb);
                    bill.setNursingDegree(nursingDegree);
                    bill.setNursingFee(nursingFeeDb);
                    bill.setMealFee(mealFee.doubleValue());
                    bill.setUserNo(userNo);
                    bill.setBillDate(date);
                    bill.setCreateTime(Util.currentDateTime());
                    dayBillMapper.insert(bill);
                    return ResultUtil.success();
                }else{
                    return ResultUtil.errorMsg("日账单已存在, userNo="+userNo+", day="+date);
                }
            }else{
                return ResultUtil.errorMsg("老人用户不存在, userNo="+userNo+", day="+date);
            }

        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultUtil.error();
        }
    }

    @Override
    public List<YlElderlyInfo> listElder() throws Exception {
        try {
            List<YlElderlyInfo> elderList = elderMapper.selectList(new QueryWrapper<YlElderlyInfo>().eq("USER_STATE","1").orderByDesc("CREATE_DATE").orderByAsc("USER_NO"));
            return elderList;
        } catch (Exception e) {
            throw new Exception(e.toString());
        }
    }

    @Override
    public List<YlBuilding> getBuildingListByPensionNo(String pensionNo) {
        QueryWrapper<YlBuilding> buildingQueryWrapper = new QueryWrapper<>();
        buildingQueryWrapper.eq("PENSION_NO", pensionNo);
        buildingQueryWrapper.eq("BUILDING_STATE", "1");
        return ylBuildingMapper.selectList(buildingQueryWrapper);
    }

    @Override
    public Result<Object> getElderlyInfoPageList(BillListVO vo) {
        Map<String, Object> params = new HashMap<>(10);
        int start = (vo.getCurrentPage() - 1) * vo.getPageSize();
        int end = vo.getPageSize();
        params.put("start", start);
        params.put("end", end);
        //设置查询条件
        setParamForQueryElderlyInfo(params, vo);
        //查询列表 和 总数
        List<Map<String, Object>> resultList = dayBillMapper.getElderlyInfoPageList(params) ;
        Integer totalCount = dayBillMapper.getElderlyInfoPageListTotalCount(params);
        return ResultUtil.getPageDataSuccess(new PageDo<>(vo.getCurrentPage(), vo.getPageSize(), totalCount, resultList));

    }

    /**
     * 设置 查询条件
     */
    private void setParamForQueryElderlyInfo(Map<String, Object> params, BillListVO vo) {
        //通过对楼苑、房间号、床号、姓名、缴费情况、欠费时间、每月未结算情况进行搜索
        //楼苑
        if (Util.isNotNull(vo.getBuildingNo())) {
            params.put("buildingNo", vo.getBuildingNo());
        }
        //房间号
        if (Util.isNotNull(vo.getRoomName())) {
            params.put("roomName", vo.getRoomName());
        }
        //床号
        if (Util.isNotNull(vo.getBedName())) {
            params.put("bedName", vo.getBedName());
        }
        //楼层
        if (Util.isNotNull(vo.getFloorNo())) {
            params.put("floorNo", vo.getFloorNo());
        }
        //姓名
//        if (Util.isNotNull(vo.getUserName())) {
//            params.put("userName", "%" + vo.getUserName() + "%");
//        }
        if (Util.isNotNull(vo.getUserName())) {
            params.put("userName", vo.getUserName());
        }
        //缴费情况
        if (Util.isNotNull(vo.getPayState())) {
            params.put("payState", vo.getPayState());
        }
        //欠费时间
        if (Util.isNotNull(vo.getArrearMonth())) {
            params.put("arrearMonth", vo.getArrearMonth());
        }
        //每月未结算情况
        if (Util.isNotNull(vo.getUnSettledMonth())) {
            params.put("unSettledMonth", vo.getUnSettledMonth());
        }


        //排序  1-默认值=‘全部’  2-费用由高到低  3-费用从低到高
        if (Util.isNotNull(vo.getSort())) {
            params.put("sort", vo.getSort());
        }

        //养老院编号
        if (Util.isNotNull(vo.getPensionNo())) {
            params.put("pensionNo", vo.getPensionNo());
        }
        if (Util.isNotNull(vo.getUserState())) {
            params.put("userState", vo.getUserState());
        }
    }

    /**
     * 查看老人 获取数据
     *
     * @param userNo userNo
     * @return Map
     * @throws Exception Exception
     */
    @Override
    public Map<String, Object> getElderlyInfoDetailByUserNo(String userNo) throws Exception {
        Map<String, Object> resultMap = new HashMap<>(10);

        YlElderlyInfo elderlyInfo = elderMapper.selectById(userNo);
        //转换数据
        transformElderlyInfoForDetail(elderlyInfo);
        //获取联系人
        List<UserInfoContact> userInfoContactList = userInfoService.getUserInfoContactByUserNo(userNo);
        elderlyInfo.setUserInfoContactList(userInfoContactList);

        //老人信息
        resultMap.put("elderlyInfo", elderlyInfo);

        //合同截止时间  和开始时间    有效合同的开始时间 算入住时间  有效合同的截至时间算截至
        YlContractInfo contractInfo = ylContractInfoMapper.selectOne(new QueryWrapper<YlContractInfo>().eq("user_no",userNo).eq("is_effective","1"));
        String endDate = contractInfo.getEndDate();
        String startDate = contractInfo.getStartDate();
        resultMap.put("endDate", transformDateForDetail(contractInfo.getEndDate()));
        resultMap.put("startDate", transformDateForDetail(startDate));

        //*********护理等级信息**********/
        YlNursingRecord nursingRecord = getNursingRecordByUserNo(userNo);
        //下次护理评估时间
        resultMap.put("nextEffectDate", transformDateForDetail(nursingRecord.getNextEffectDate()));
        //护理等级No
        resultMap.put("nursingCostNo", getYlCostByCostNo(nursingRecord.getCostNo()).getCostNo());
        //护理等级
        resultMap.put("nursingCostName", getYlCostByCostNo(nursingRecord.getCostNo()).getCostName());
        //护理护理评估生效日期
        resultMap.put("nursingEffectDate", transformDateForDetail(nursingRecord.getEffectDate()));
        YlStaffInfo staffInfo = getStaffInfo(nursingRecord.getStaffNo());
        //护理人员名称
        resultMap.put("staffName", Util.isNull(staffInfo) ? "" : staffInfo.getStaffName());

        //*********长护险等级信息**********/
        YlAssessmentRecord assessmentRecord = getAssessmentRecordByUserNo(userNo);
        //长护险评估等级
        resultMap.put("assessmentCostName", getYlCostByCostNo(assessmentRecord.getCostNo()).getCostName());
        //评估有效期
        resultMap.put("validDate", transformDateForDetail(assessmentRecord.getValidDate()));

        //床位信息：楼苑/房间号/床位
        Map<String, Object> buildingRoomBed = ylElderlyInfoMapper.getBuildingInfoByUserNo(userNo);
        resultMap.put("buildingInfo", buildingRoomBed.get("buildingInfo"));
        // 养老院 - 床位信息
        resultMap.put("buildingRoomBedInfo", buildingRoomBed);

        //*********结算年份月份区间**********/
        //默认结算开始日期 为 住院合同合同开始
        String hospitalStartDate = startDate;
        //默认结算结束日期 为 住院合同结束 ,如果合同还未结束，以当前时间 为 结算结束日期
        String hospitalEndDate = Long.parseLong(endDate) > Long.parseLong(Util.currentDate()) ? Util.currentDate() : endDate;
        //获取结算开始日期，结束日期的年份月份区间
        List<Map<String,Object>> yearArr = getYearArrOfDayInterval(hospitalStartDate,hospitalEndDate);
        resultMap.put("settleYearArr", yearArr);
        resultMap.put("selectCurYear", yearArr.size()>0?yearArr.get(yearArr.size()-1).get("year"):Util.currentYear());

        //*********财务明细-总费用、实缴费、应缴款**********/
        //总费用
        double totalAmt = monthBillMapper.getUserTotalAmt(userNo);
        //实缴费
        double realPayAmt = payRecordMapper.getUserTotalPayAmt(userNo);
        //需缴费
        double needPayAmt = totalAmt-realPayAmt;
        //上月结余
        double balance = realPayAmt-totalAmt;
        //获取月份未结算
        int unsettledMonth = getlastUnsettedMonth(userNo);

        resultMap.put("totalAmt", totalAmt);
        resultMap.put("realPayAmt", realPayAmt);
        resultMap.put("needPayAmt", needPayAmt);
        resultMap.put("balance", balance);
        resultMap.put("unsettledMonth", unsettledMonth);
        return resultMap;
    }

    @Override
    public Result<Object> getMonthArrOfBillYear(String userNo, long year) {
        try {
            Map<String, Object> resultMap = new HashMap<>(10);
            //合同截止时间  和开始时间    有效合同的开始时间 算入住时间  有效合同的截至时间算截至
            YlContractInfo contractInfo = ylContractInfoMapper.selectOne(new QueryWrapper<YlContractInfo>().eq("user_no",userNo).eq("is_effective","1"));
            String endDate = contractInfo.getEndDate();
            String startDate = contractInfo.getStartDate();

            //*********结算年份月份区间**********/
            //默认结算开始日期 为 住院合同合同开始
            String hospitalStartDate = startDate;
            //默认结算结束日期 为 住院合同结束 ,如果合同还未结束，以当前时间 为 结算结束日期
            String hospitalEndDate = Long.parseLong(endDate) > Long.parseLong(Util.currentDate()) ? Util.currentDate() : endDate;
            //获取结算开始日期，结束日期的年份月份区间
            List<Map<String,Object>> list = getYearMonthArrOfDayInterval(hospitalStartDate,hospitalEndDate);
            for (Map<String,Object> map:list) {
                long tmpYear = (long) map.get("year");
                //返回指定年的月份信息
                if(tmpYear==year){
                    resultMap.put("data1",map.get("data"));
                    resultMap.put("data2",map.get("data2"));
                    break;
                }
            }
            return ResultUtil.success(200,"查询成功",resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.error();
        }
    }

    @Override
    public Result<Object> getUserMonthSettleInfo(String userNo, int year, int month) throws Exception {
        Map<String, Object> retMap = new HashMap<>();
        try {
            //获取该结算月份是否已结算
            int state = getMonthSettleExist(userNo,year,month);
            //获取本月实缴金额
            double realPayAmt = 0;

            //结算信息初始化
            //获取结算月份初始天数
            int count = dayBillMapper.selectCount(new QueryWrapper<YlDayBill>().eq("user_no",userNo).likeRight("bill_date",String.valueOf(year)+formatMonth(month)));
            retMap.put("calcuDay", count);
            retMap.put("initInfo", dayBillMapper.getUserInitMonthBill(userNo,year,month)); //结算总信息初始化
            retMap.put("initDayInfo", getCurDayFeeInfo(userNo,year,month));//结算日标准费用初始化

            //*********财务明细-总费用、实缴费、应缴款**********/
            Map<String,Object> tabMap = new HashMap<>();
            double totalAmt = monthBillMapper.getUserTotalAmt(userNo);              //总费用
            double realTotalPayAmt = payRecordMapper.getUserTotalPayAmt(userNo);    //实缴费
            //总费用小于等于实缴款时，需缴费为0；总费用大于等于实缴款是，需缴费=总费用-实缴费
            double needPayAmt = totalAmt<=realTotalPayAmt?0:MathExtend.subtract(totalAmt,realTotalPayAmt);
            //获取上月结余
            YlElderlyBill bill = ylElderlyBillMapper.selectById(userNo);
            double billBalance = bill.getBillBalance();
            //获取月份未结算
            int unsettledMonth = getlastUnsettedMonth(userNo);

            tabMap.put("tabTotalAmt",totalAmt);
            tabMap.put("tabRealPayAmt",realTotalPayAmt);
            tabMap.put("tabNeedPayAmt",needPayAmt);
            tabMap.put("tabBalance",billBalance);
            tabMap.put("tabUnsettledMonth",unsettledMonth);
            retMap.put("tab",tabMap);

            if(state==1){
                YlMonthBill monthBill = monthBillMapper.selectOne(new QueryWrapper<YlMonthBill>().eq("user_no",userNo).eq("bill_year",year).eq("bill_month",month));
                //获取本月实缴金额
                realPayAmt = payDtRecordMapper.getmonthPayAmt(monthBill.getId());
                retMap.put("bill", monthBill);
            }
            retMap.put("realPayAmt",realPayAmt);
            retMap.put("state", state);
            return ResultUtil.success("data",retMap);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.error();
        }
    }

    @Override
    @Transactional
    public Result<Object> createMonthBill(YlMonthBill bill, int tellerNo) throws Exception {
        try {
            int unsettledMonth = getlastUnsettedMonth(bill.getUserNo());            //获取最早的未结算月份
            if(unsettledMonth!=bill.getBillMonth()){
                return ResultUtil.errorMsg("当前月前存在未结算的月份，请先结算前面的月！");
            }

            bill.setOwingMoney("1"); //1-欠费
            bill.setTellerNo(String.valueOf(tellerNo));
            bill.setCreateTime(Util.currentDateTime());
            bill.setInitCurMonthFee(bill.getCurMonthFee());
            monthBillMapper.insert(bill);


            if(bill.getLastBalance().doubleValue()<=0){       //账单上月结余小于等于0时，只结算
                //设置老人账单汇总信息
                YlElderlyBill elderBill = ylElderlyBillMapper.selectById(bill.getUserNo());
                if(elderBill!=null){
                    //设置账户余额
                    double billBalance = MathExtend.subtract(elderBill.getBillBalance(), bill.getInitCurMonthFee().doubleValue());
                    elderBill.setBillBalance(billBalance);
                    //设置总月账单费用
                    double totalMonthFee = MathExtend.add(elderBill.getTotalMonthFee(), bill.getInitCurMonthFee().doubleValue());
                    elderBill.setTotalMonthFee(totalMonthFee);
                    //设置最后结算年
                    elderBill.setFinalSettleYear(bill.getBillYear());
                    //设置最后结算月
                    elderBill.setFinalSettleMonth(bill.getBillMonth());
                    //设置缴费状态
                    if(elderBill.getBillBalance()>0){
                        elderBill.setBillState("1");//1-余额
                    }else if(elderBill.getBillBalance()==0){
                        elderBill.setBillState("0");//0-结清
                    }else{
                        elderBill.setBillState("2");//2-欠费
                    }
                    ylElderlyBillMapper.updateById(elderBill);
                }
            }else{      //账单余额大于0时，结算并扣费
                //生成缴费流水
                List<YlPaymentRecord> recordList = payRecordMapper.selectList(new QueryWrapper<YlPaymentRecord>().eq("PAY_STATUS","0").orderByAsc("CREATE_TIME").orderByAsc("ID"));
                if(recordList.size()>0){
                    //获取最老的一笔可缴费的记录
                    YlPaymentRecord record = recordList.get(0);
                    //获取该笔缴费记录的缴费余额
                    Map<String,Object> payAmtInfo = payRecordMapper.getPaymentRecordSum(record.getId());
                    double payInit = ((BigDecimal) payAmtInfo.get("unpayAmt")).doubleValue();       //缴费余额
                    double curMonthFee = bill.getCurMonthFee().doubleValue();                       //当月账单金额
                    //如果账单金额大于缴费余额，实际支付金额为缴费余额；如果账单金额小于缴费余额，实际支付金额为账单金额
                    double realPay = curMonthFee>payInit?payInit:curMonthFee;
                    double payAfter = MathExtend.subtract(payInit,realPay);     //扣费后缴费余额

                    //如果账单金额小于等于缴费金额，账单欠费状态改为0
                    if(curMonthFee<=payInit){
                        bill.setOwingMoney("0");
                        monthBillMapper.updateById(bill);
                    }

                    //新增账单详细流水
                    YlPaymentDetailRecord dr = new YlPaymentDetailRecord();
                    dr.setMonthBillId(bill.getId());
                    dr.setRecordId(record.getId());
                    dr.setPayAmt(new BigDecimal(realPay));
                    dr.setPayDay(Util.currentDate());
                    dr.setCreateTime(Util.currentDateTime());
                    dr.setTellerNo(String.valueOf(tellerNo));
                    dr.setStatus("1"); //正常
                    payDtRecordMapper.insert(dr);

                    //设置老人账单汇总信息
                    YlElderlyBill elderBill = ylElderlyBillMapper.selectById(record.getUserNo());
                    if(elderBill!=null){
                        //设置账户余额
                        double billBalance = MathExtend.subtract(elderBill.getBillBalance(), bill.getInitCurMonthFee().doubleValue());
                        elderBill.setBillBalance(billBalance);
                        //设置总月账单费用
                        double totalMonthFee = MathExtend.add(elderBill.getTotalMonthFee(), bill.getInitCurMonthFee().doubleValue());
                        elderBill.setTotalMonthFee(totalMonthFee);
                        //设置最后结算年
                        elderBill.setFinalSettleYear(bill.getBillYear());
                        //设置最后结算月
                        elderBill.setFinalSettleMonth(bill.getBillMonth());
                        //设置缴费状态
                        if(elderBill.getBillBalance()>0){
                            elderBill.setBillState("1");//1-余额
                        }else if(elderBill.getBillBalance()==0){
                            elderBill.setBillState("0");//0-结清
                        }else{
                            elderBill.setBillState("2");//2-欠费
                        }
                        //设置实际支付金额
                        double totalRealpayFee = MathExtend.add(elderBill.getTotalRealpayFee(),realPay);
                        elderBill.setTotalRealpayFee(totalRealpayFee);
                        ylElderlyBillMapper.updateById(elderBill);
                    }
                }
            }

            return ResultUtil.success();
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultUtil.error();
        }
    }

    @Override
    public Result<Object> getUserBillAbleDay(String userNo) throws Exception {
        try {
            int unsettledMonth = getlastUnsettedMonth(userNo);            //获取最早的未结算月份
            return ResultUtil.success("data",Util.currentYear()+"-"+String.valueOf(unsettledMonth)+"-"+"01");
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.error();
        }
    }

    @Override
    @Transactional
    public Result<Object> createPaymentRecord(YlPaymentRecord record, int tellerNo) throws Exception {
        try {
            record.setTellerNo(String.valueOf(tellerNo));
            record.setStatus("1"); //正常
            record.setCreateTime(Util.currentDateTime());
            record.setPayStatus("0");//未扣完
            payRecordMapper.insert(record);

            double payInit = record.getPaymentCount().doubleValue();    //初始支付账单金额
            double realMonthPay = 0;                                    //实际支付月金额
            double realPay = 0;                                         //实际支付金额

            //查询该用户未缴费的账单，按缴费年份月份正序排序
            QueryWrapper qw = new QueryWrapper<YlMonthBill>();
            qw.eq("user_no", record.getUserNo());
            qw.eq("owing_money","1");
            qw.orderByAsc("BILL_YEAR");
            qw.orderByAsc("BILL_MONTH");
            //循环扣费（对账单按照年份月份顺序扣费）
            List<YlMonthBill> billList = monthBillMapper.selectList(qw);
            for (int i = 0; i < billList.size(); i++) {
                YlMonthBill tmpBill = billList.get(i);
                double curMonthFee = tmpBill.getCurMonthFee().doubleValue();
                //如果账单金额大于缴费金额，实际支付金额为缴费金额；如果账单金额小于缴费金额，实际支付金额为账单金额
                realMonthPay = curMonthFee>payInit?payInit:curMonthFee;
                payInit = MathExtend.subtract(payInit,realMonthPay); //初始支付金额=初始支付金额-每月实际支付金额
                realPay = MathExtend.add(realPay,realMonthPay);      //实际支付金额=实际支付金额+每月实际支付金额

                //如果账单金额小于等于缴费金额，账单欠费状态改为0
                if(curMonthFee<=payInit){
                    tmpBill.setOwingMoney("0");
                    monthBillMapper.updateById(tmpBill);
                }

                //新增账单详细流水
                YlPaymentDetailRecord dr = new YlPaymentDetailRecord();
                dr.setMonthBillId(tmpBill.getId());
                dr.setRecordId(record.getId());
                dr.setPayAmt(new BigDecimal(realMonthPay));
                dr.setPayDay(Util.currentDate());
                dr.setCreateTime(Util.currentDateTime());
                dr.setTellerNo(String.valueOf(tellerNo));
                dr.setStatus("1"); //正常
                payDtRecordMapper.insert(dr);

                //缴费金额用完时，退出循环扣费
                if(payInit==0){
                    record.setPayStatus("1");//已扣完
                    payRecordMapper.updateById(record);
                    break;
                }
            }

            //设置老人账单汇总信息
            YlElderlyBill elderBill = ylElderlyBillMapper.selectById(record.getUserNo());
            if(elderBill!=null){
                //设置账户余额
                double billBalance = MathExtend.add(elderBill.getBillBalance(), record.getPaymentCount().doubleValue());
                elderBill.setBillBalance(billBalance);
                //设置缴费状态
                if(elderBill.getBillBalance()>0){
                    elderBill.setBillState("1");//1-余额
                }else if(elderBill.getBillBalance()==0){
                    elderBill.setBillState("0");//0-结清
                }else{
                    elderBill.setBillState("2");//2-欠费
                }
                //设置支付费用
                double totalPayFee= MathExtend.add(elderBill.getTotalPayFee(),record.getPaymentCount().doubleValue());
                elderBill.setTotalPayFee(totalPayFee);
                //设置实际支付金额
                double totalRealpayFee = MathExtend.add(elderBill.getTotalRealpayFee(),realPay);
                elderBill.setTotalRealpayFee(totalRealpayFee);
                ylElderlyBillMapper.updateById(elderBill);
            }

            return ResultUtil.success();
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultUtil.error();
        }
    }

    @Override
    public IPage<Map<String, Object>> pageBillMaps(String startDay, String endDay, String userNo, int page, int limit) throws Exception{
        try {
            Page<YlPaymentRecord> pageCondition = new Page<>(page,limit);
            QueryWrapper<YlPaymentRecord> qw = new QueryWrapper<>();
            if(StringUtils.isNotBlank(startDay)&& StringUtils.isNotBlank(endDay)){
                qw.ge("payment_day",startDay);
                qw.le("payment_day",endDay);
            }
            if(StringUtils.isNotBlank(userNo)){
                qw.eq("user_no",userNo);
            }else{
                //用户编号为空时，不允许查出数据
                qw.eq("user_no",0);
            }
            qw.eq("status","1").orderByDesc("CREATE_TIME");
            IPage<Map<String,Object>> billPage = payRecordMapper.selectMapsPage(pageCondition, qw);
            billPage.getRecords().forEach(obj->{
                String tellerNo = (String)obj.get("TELLER_NO");
                obj.put("PAYMENT_DAY", Util.simpleDate((String)obj.get("PAYMENT_DAY")));
                obj.put("CREATE_TIME", Util.simpleDate((String)obj.get("CREATE_TIME")));
                SysUser user = sysUserMapper.selectById(tellerNo);
                if(user!=null){
                    obj.put("TELLER_NAME",user.getUserName());
                }
            });
            return billPage;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.toString());
        }
    }

    @Override
    public Result<Object> test(String userNo) throws Exception {
        //查询该用户未缴费的账单，按缴费年份月份正序排序
        QueryWrapper qw = new QueryWrapper<YlMonthBill>();
        qw.eq("user_no", userNo);
        qw.eq("owing_money","1");
        qw.orderByAsc("bill_year");
        qw.orderByAsc("bill_month");
        //循环扣费（对账单按照年份月份顺序扣费）
        List<YlMonthBill> billList = monthBillMapper.selectList(qw);
        Util.pringJson(billList,"arr");
        return ResultUtil.success("data",billList);
    }

    //通过年份月份获取该月有多少天
    private int getDaysOfYearMonth(int year, int month) throws Exception{
        try {
            String day = String.valueOf(year)+String.valueOf(month)+"01";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(sdf.parse(day));
            return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new Exception(e.toString());
        }

    }

    //转换费用等级格式
    private String formatDegree(long num){
        if(num==0){
            return "";
        }else{
            return num+"";
        }
    }

    /**
     * yyyyMMdd -> yyyy-MM-dd
     *
     * @param date date
     * @return String
     */
    private String transformDateForDetail(String date) {
        if (Util.isNull(date)) {
            return "";
        }
        return LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    /**
     * 获取 label
     *
     * @param labelCode labelCode
     * @return YsLabel
     */
    private YsLabel getYsLabelByLabelCode(String labelCode) {
        QueryWrapper<YsLabel> labelQueryWrapper = new QueryWrapper<>();
        if (Util.isNotNull(labelCode)) {
            labelQueryWrapper.eq("LABEL_CODE", labelCode);
            labelQueryWrapper.eq("STATUS", "1");
        }
        return ysLabelMapper.selectOne(labelQueryWrapper);
    }

    /**
     * 获取 合同 集合
     *
     * @param userNo userNo
     * @return List
     */
    private List<YlContractInfo> getContractInfoByUserNo(String userNo) {
        QueryWrapper<YlContractInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("USER_NO", userNo);
        queryWrapper.orderByDesc("CREATE_TIME");

        return ylContractInfoMapper.selectList(queryWrapper);
    }

    /**
     * 获取护理信息
     *
     * @param userNo userNo
     * @return YlNursingRecord
     */
    private YlNursingRecord getNursingRecordByUserNo(String userNo) {
        QueryWrapper<YlNursingRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("USER_NO", userNo);
        queryWrapper.eq("is_effective", "1");
        return ylNursingRecordMapper.selectOne(queryWrapper);
    }

    /**
     * 获取护理人员信息
     *
     * @param staffNo staffNo
     * @return YlStaffInfo
     */
    private YlStaffInfo getStaffInfo(String staffNo) {
        QueryWrapper<YlStaffInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("STAFF_NO", staffNo);
        queryWrapper.eq("STAFF_STATE", "1");
        return ylStaffInfoMapper.selectOne(queryWrapper);
    }


    /**
     * 获取评估信息
     *
     * @param userNo userNo
     * @return YlAssessmentRecord
     */
    private YlAssessmentRecord getAssessmentRecordByUserNo(String userNo) {
        QueryWrapper<YlAssessmentRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("USER_NO", userNo);
        queryWrapper.eq("is_effective", "1");
        return ylAssessmentRecordMapper.selectOne(queryWrapper);
    }

    /**
     * 获取费用 数据
     *
     * @param costNo costNo
     * @return YlCost
     */
    private YlCost getYlCostByCostNo(String costNo) {
        QueryWrapper<YlCost> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("COST_NO", costNo);
        queryWrapper.eq("STATUS", "1");
        return ylCostMapper.selectOne(queryWrapper);
    }


    /**
     * 功能描述: 功能描述: 获取日期区间所在年份，月份数组
     * @Param:  [startDay 开始日期, endDay 结束日期]
     * @Author: szt
     * @Date:   2020/11/27
     */
    public static List<Map<String,Object>> getYearMonthArrOfDayInterval(String startDay, String endDay) throws Exception {
        List<Map<String,Object>> list = new ArrayList<>();
        //初始化
        //获取开始年份、结束年份、开始年月、结束年月
        long startYear = Long.parseLong(startDay.substring(0,4));
        long endYear = Long.parseLong(endDay.substring(0,4));
        long startYearMonth = Long.parseLong(startDay.substring(0,6));
        long endYearMonth = Long.parseLong(endDay.substring(0,6));
        long tmpYear = 0;
        long tmpYearMonth = 0;
        //如果传入开始日期、结算日期相反，进行置换
        if(startYear> endYear){
            tmpYear = startYear;
            startYear = endYear;
            endYear = tmpYear;
            tmpYearMonth = startYearMonth;
            startYearMonth = endYearMonth;
            endYearMonth = tmpYearMonth;
        }
        //计算年份差
        long yearDiff = endYear - startYear;
        for (long i = 0; i <= yearDiff; i++) {
            Map<String,Object> map = new HashMap<>();
            map.put("year", startYear+i);
            List<Map<String,Object>> innerList = new ArrayList<>();
            List<Map<String,Object>> inner2List = new ArrayList<>();

            if(yearDiff==0){  //当年份差等于0时，1月-合同起始月 状态为未入住，合同起始月-合同结束月（截止当年当月） 状态为入住，合同结束月（截止当年当月）-12月，状态为未入住
                startYearMonth -= startYear*100;
                endYearMonth -=endYear*100;
                int count=1;
                for (long j = 1; j < startYearMonth; j++) {
                    Map<String,Object> innerMap = new HashMap<>();
                    innerMap.put("month",j);
                    innerMap.put("status","0");
                    Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                    count++;
                }
                for (long j = startYearMonth; j <= endYearMonth; j++) {
                    Map<String,Object> innerMap = new HashMap<>();
                    innerMap.put("month",j);
                    innerMap.put("status","1");
                    Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                    count++;
                }
                for (long j = endYearMonth+1; j <= 12; j++) {
                    Map<String,Object> innerMap = new HashMap<>();
                    innerMap.put("month",j);
                    innerMap.put("status","0");
                    Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                    count++;
                }
            }else{
                if(i==0){   //当年份差大于0时，首年 1月-合同起始月 状态为未入住, 合同起始月-合同结束月（截止当年当月） 状态为入住
                    startYearMonth -= startYear*100;
                    int count=1;
                    for (long j = 1; j < startYearMonth; j++) {
                        Map<String,Object> innerMap = new HashMap<>();
                        innerMap.put("month",j);
                        innerMap.put("status","0");
                        Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                        count++;
                    }
                    for (long j = startYearMonth; j <= 12; j++) {
                        Map<String,Object> innerMap = new HashMap<>();
                        innerMap.put("month",j);
                        innerMap.put("status","1");
                        Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                        count++;
                    }
                }else if(i==yearDiff){  //当年份差大于0时，末年 1月-合同结束月（截止当年当月） 状态为入住，合同结束月（截止当年当月）-12月，状态为未入住
                    endYearMonth -= endYear*100;
                    int count=1;
                    for (long j = 1; j <= endYearMonth; j++) {
                        Map<String,Object> innerMap = new HashMap<>();
                        innerMap.put("month",j);
                        innerMap.put("status","1");
                        Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                        count++;
                    }
                    for (long j = endYearMonth+1; j <=12 ; j++) {
                        Map<String,Object> innerMap = new HashMap<>();
                        innerMap.put("month",j);
                        innerMap.put("status","0");
                        Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                        count++;
                    }
                }else{  //当年份差大于0时，非首年末年 状态为入住
                    int count=1;
                    for (long j = 1; j <= 12; j++) {
                        Map<String,Object> innerMap = new HashMap<>();
                        innerMap.put("month",j);
                        innerMap.put("status",1);
                        Object object = count<=6?innerList.add(innerMap):inner2List.add(innerMap);
                        count++;
                    }

                }
            }

            map.put("data",innerList);
            map.put("data2",inner2List);
            list.add(map);
        }
        return list;
    }

    /**
     * 功能描述: 功能描述: 获取日期区间所在年份，月份数组
     * @Param:  [startDay 开始日期, endDay 结束日期]
     * @Author: szt
     * @Date:   2020/11/27
     */
    public static List<Map<String,Object>> getYearArrOfDayInterval(String startDay, String endDay) throws Exception {
        List<Map<String,Object>> list = new ArrayList<>();
        //初始化
        //获取开始年份、结束年份、开始年月、结束年月
        long startYear = Long.parseLong(startDay.substring(0,4));
        long endYear = Long.parseLong(endDay.substring(0,4));
        long tmpYear = 0;
        //如果传入开始日期、结算日期相反，进行置换
        if(startYear> endYear){
            tmpYear = startYear;
            startYear = endYear;
            endYear = tmpYear;
        }
        //计算年份差
        long yearDiff = endYear - startYear;
        for (long i = 0; i <= yearDiff; i++) {
            Map<String,Object> map = new HashMap<>();
            map.put("year", startYear+i);
            list.add(map);
        }
        return list;
    }



    /**
     * 转换 成页面 数据
     *
     * @param elderlyInfo elderlyInfo
     * @throws Exception Exception
     */
    private void transformElderlyInfoForDetail(YlElderlyInfo elderlyInfo) throws Exception {
        //身份证
        if (Util.isNotNull(elderlyInfo.getUserPid())) {
            elderlyInfo.setUserPid(AesMyUtil.Decrypt(elderlyInfo.getUserPid()));
        }
        //教育程度
        if (Util.isNotNull(elderlyInfo.getEducation())) {
            elderlyInfo.setEducation(getYsLabelByLabelCode(elderlyInfo.getEducation()).getLabelName());
        }
        //民族
        if (Util.isNotNull(elderlyInfo.getNation())) {
            elderlyInfo.setNation(getYsLabelByLabelCode(elderlyInfo.getNation()).getLabelName());
        }
        //户籍类型
        if (Util.isNotNull(elderlyInfo.getHouseholdRegister())) {
            elderlyInfo.setHouseholdRegister(getYsLabelByLabelCode(elderlyInfo.getHouseholdRegister()).getLabelName());
        }
        //社保类型
        if (Util.isNotNull(elderlyInfo.getSocialSecurityType())) {
            elderlyInfo.setSocialSecurityType(getYsLabelByLabelCode(elderlyInfo.getSocialSecurityType()).getLabelName());
        }
        //认知
        if (Util.isNotNull(elderlyInfo.getCognitionStatus())) {
            elderlyInfo.setCognitionStatus(CognitionStatusEnum.getName(elderlyInfo.getCognitionStatus()));
        }
        //性别
        if (Util.isNotNull(elderlyInfo.getUserSex())) {
            elderlyInfo.setUserSex(SexTypeEnum.getName(elderlyInfo.getUserSex()));
        }
        //缴费日期
        if (Util.isNotNull(elderlyInfo.getPaymentDate())) {
            elderlyInfo.setPaymentDate(transformDateForDetail(elderlyInfo.getPaymentDate()));
        }
        //退住时间
        if (Util.isNotNull(elderlyInfo.getStayBackDate())) {
            elderlyInfo.setStayBackDate(transformDateForDetail(elderlyInfo.getStayBackDate()));
        }
        //死亡时间
        if (Util.isNotNull(elderlyInfo.getDeathDate())) {
            elderlyInfo.setDeathDate(transformDateForDetail(elderlyInfo.getDeathDate()));
        }

    }

    /**
     * 功能描述: 获取最近未结算的月份
     * @Param:  [hospitalStartDate 入住日期， userNo 用户编号]
     * @Author: szt
     * @Date:   2020/11/29
     */
    private int getlastUnsettedMonth(String userNo) throws Exception{
        try {
            //合同截止时间  和开始时间    有效合同的开始时间 算入住时间  有效合同的截至时间算截至
            Map<String,Object> tabMap = new HashMap<>();

            YlContractInfo contractInfo = ylContractInfoMapper.selectOne(new QueryWrapper<YlContractInfo>().eq("user_no",userNo).eq("is_effective","1"));
            String startDate = contractInfo.getStartDate();
            int hospitalStartMonth = Integer.parseInt(startDate.substring(4,6));
            int month=0;
            List<Map<String,Object>> list = monthBillMapper.listUserMonthAmt(userNo);
            for (int i = 0; i < list.size(); i++) {
                int is_exist = (int)list.get(i).get("is_exist");
                if(is_exist==0){
                    long monthLg = (long)list.get(i).get("month");
                    if(monthLg>=hospitalStartMonth){
                        month = (int)monthLg;
                        break;
                    }
                }
            }
            return month;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.toString());
        }
    }

    /**
     * 功能描述: 获取月份
     * @Param:  [hospitalStartDate 入住日期， userNo 用户编号]
     * @Author: szt
     * @Date:   2020/11/29
     */
    private int getMonthSettleExist(String userNo, int year, int month) throws Exception{
        try {
            YlMonthBill bill = monthBillMapper.selectOne(new QueryWrapper<YlMonthBill>().eq("user_no",userNo).eq("bill_month",month).eq("bill_year",year));
            if(bill!=null){
                return 1;
            }else{
                return 0;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e.toString());
        }
    }

    /**
     * 功能描述: 获取单日账单费用标准
     * @Param:  [userNo, year, month]
     * @Author: szt
     * @Date:   2020/11/30
     */
    private Map<String,Object> getCurDayFeeInfo(String userNo, int year, int month) throws Exception{
        String day = String.valueOf(year)+String.valueOf(month)+"01";
        Map<String,Object> info = dayBillMapper.createDayBill(userNo, day);
        int dayCount = Util.getDaysOfMonth(day); //获取日账单所在月天数
        BigDecimal bedFee = (BigDecimal) info.get("bed_fee");
        double bedFeeDb = MathExtend.divide(bedFee.doubleValue(),(double)dayCount,2);  //计算床位费（床位月费/月天数）
        BigDecimal nursingFee = (BigDecimal)info.get("nurse_fee");
        double nursingFeeDb =  MathExtend.divide(nursingFee.doubleValue(),(double)dayCount,2); //计算护理费（护理月费/月天数）
        BigDecimal assementFee = (BigDecimal)info.get("assess_fee");
        double assementFeeDb =  MathExtend.divide(assementFee.doubleValue(),(double)dayCount,2); //计算长护险费（长护险月费/月天数）

        info.put("bed_fee",bedFeeDb);
        info.put("nurse_fee",nursingFeeDb);
        info.put("assess_fee",assementFeeDb);
        return info;
    }

    /**
     * 功能描述: 格式化月份，月份为个位数时，前补0
     * @Param:  [month]
     * @Author: szt
     * @Date:   2020/11/30
     */
    private String formatMonth(int month){
        if(String.valueOf(month).length()==1){
            return "0"+String.valueOf(month);
        }else{
            return String.valueOf(month);
        }
    }

    /*
     * 获取上月结余
     */
    private Map<String,Object> getReflashMonthBillData(YlMonthBill bill, double pay){
        Map<String,Object> settleMap = new HashMap<>();
        double curMonthFee=0;
        double lastBalance=0;
        double curRealPayFee=0;
        double curTotalFee=0;
        double curBalance=0;
        String owingMoney="1";

        if(bill!=null){
            BigDecimal curMonthFeeBd = bill.getCurMonthFee();     //本月费用
            BigDecimal lastBalanceBd = bill.getLastBalance();     //上月结余
            BigDecimal curRealPayFeeBd = bill.getCurRealPayFee(); //本月实缴费用
            BigDecimal curTotalFeeBd = bill.getCurTotalFee();     //本月总费用合计
            BigDecimal curBalanceBd = bill.getCurBalance();       //本月结余
            BigDecimal payBd = new BigDecimal(pay);               //实际扣款

            //上月账单不存在时
            curMonthFee = MathExtend.subtract(curMonthFeeBd.doubleValue(),pay);  //本月费用 = 本月费用 - 实际扣款
            lastBalance = MathExtend.add(lastBalanceBd.doubleValue(),pay);       //上月结余 = 上月结余 + 实际扣款
            curRealPayFee = pay;                                                 //本月实缴费用=实际扣款
            //本月费用合计
            //如果上月结余是正，上月结余-本月费用>=0, 显示0；上月结余-本月费用<0, 显示本月费用-上月结余
            curTotalFee = MathExtend.add(curMonthFee,lastBalance);               //本月总费用合计=本月费用+上月结余
            //curBalance = MathExtend.add(lastBalance,curNeedPayFee);              //本月结余=上月结余+本月应缴费用
            //本月余额为0时，账单扣费状态改为不欠费
            if(curBalance==0){
                owingMoney="0";
            }
        }

//            if(bill!=null){
//                BigDecimal oldCurMonthFeeBd = lastBill.getCurMonthFee();        //本月费用 (老账单)
//                BigDecimal oldLastBalanceBd = lastBill.getLastBalance();        //上月结余 (老账单)
//                BigDecimal oldCurRealPayFeeBd = lastBill.getCurRealPayFee();    //本月实缴费用 (老账单)
//                BigDecimal oldCurTotalFeeBd = lastBill.getCurTotalFee();        //本月总费用合计 (老账单)
//                BigDecimal oldCurNeedPayFeeBd = lastBill.getCurNeedPayFee();    //本月应缴费用 (老账单)
//                BigDecimal oldCurBalanceBd = lastBill.getCurBalance();          //本月结余 (老账单)
//
//                BigDecimal curMonthFeeBd = bill.getCurMonthFee();     //本月费用
//                BigDecimal lastBalanceBd = bill.getLastBalance();     //上月结余
//                BigDecimal curRealPayFeeBd = bill.getCurRealPayFee(); //本月实缴费用
//                BigDecimal curTotalFeeBd = bill.getCurTotalFee();     //本月总费用合计
//                BigDecimal curNeedPayFeeBd = bill.getCurNeedPayFee(); //本月应缴费用
//                BigDecimal curBalanceBd = bill.getCurBalance();       //本月结余
//
//                BigDecimal payBd = new BigDecimal(pay);               //实际扣款
//
//                //上月账单存在时
//                curMonthFee = MathExtend.subtract(curMonthFeeBd.doubleValue(),pay);  //本月费用=本月费用-实际扣款
//                lastBalance = 0;                                                     //上月结余为0 （扣款顺序是按月一月月清，扣到本月时，上月已经清了）
//                curRealPayFee = pay;                                                 //本月实缴费用=实际扣款
//                curTotalFee = MathExtend.add(curMonthFee,lastBalance);               //本月总费用合计=本月费用+上月结余
//                curNeedPayFee = MathExtend.subtract(curMonthFee,curRealPayFee);      //本月应缴费用=本月费用-本月实缴费用
//                curBalance = MathExtend.add(lastBalance,curNeedPayFee);              //本月结余=上月结余+本月应缴费用
//            }

        settleMap.put("curMonthFee",curMonthFee);
        settleMap.put("lastBalance",lastBalance);
        settleMap.put("curRealPayFee",curRealPayFee);
        settleMap.put("curTotalFee",curTotalFee);
        settleMap.put("curBalance",curBalance);
        settleMap.put("owingMoney",owingMoney);
        return settleMap;
    }
}
